#ifndef _UI_TEXT_H_
#define _UI_TEXT_H_

#include "math/vec2.h"
#include "input/keyboard.h"
#include <string>
#include "graphics/color.h"

class Font;


namespace ui
{
class UISprite;
class UIWidget;
class UIText
{
public:
	enum		TEXT_JUST_HORIZ
	{
		TJH_CENTER,
		TJH_LEFT,
		TJH_RIGHT,
		TJH_COUNT
	};
	enum		TEXT_JUST_VERT
	{
		TJV_CENTER,
		TJV_TOP,
		TJV_BOTTOM,
		TJV_COUNT
	};
/*	enum		TEXT_FLAGS
	{
		FLAG_TOP                      = 0x00000000,
		FLAG_LEFT                     = 0x00000000,
		FLAG_CENTER                   = 0x00000001,
		FLAG_RIGHT                    = 0x00000002,
		FLAG_VCENTER                  = 0x00000004,
		FLAG_BOTTOM                   = 0x00000008,
		FLAG_WORDBREAK                = 0x00000010,
		FLAG_SINGLELINE               = 0x00000020,
		FLAG_EXPANDTABS               = 0x00000040,
		FLAG_TABSTOP                  = 0x00000080,
		FLAG_NOCLIP                   = 0x00000100
	};
*/	
	static const int	DEFAULT_MAX_INPUT_LEN = 256;

					UIText();
					~UIText();
					/// automatically calls Tick as well.
	bool			Render();
	bool			IsInside(const math::Vec2& Point);

	void			SetText(const std::wstring& Text);
	void			AppendText(const std::wstring& Text);
	void			SetFont(const std::string& Font);
	
	void			SetFontD(Font* pFont) { m_pFont = pFont; };
	Font*		GetFont() const;
	const std::string& GetFontName() const;
	void			SetPos(const math::Vec2& Pos);
	void			SetColor(COLOR  Color) { m_Color = Color; };
	bool			IsEmpty() { return m_Text.empty(); };
	void			SetTextOffset(const math::Vec2& Offset) { m_Offset = Offset; };

	/// accessors
	const math::Vec2&	GetPos() const { return  m_Pos;	 };
	const math::Vec2&	GetSize() const { return  m_Size; };
	const std::wstring&	GetText() const { return m_Text; };
	const std::wstring&	GetOrigText() const { return m_OriginalText; };
	const COLOR		GetColor() const { return m_Color; };
	const math::Vec2&	GetBorder() const { return m_Border; }

	void			SetBorder(const math::Vec2& Size) { m_Border = Size; };

	const int		GetMaxInputLen() const	{ return m_MaxInputLen; }
	void			SetMaxInputLen(int len)	{ m_MaxInputLen = len; }

	// justification and extents
	void			SetVertJust(TEXT_JUST_VERT v) { m_VertJust = v;  CalcExtents(); };
	void			SetVertJust(const std::string& Text);
	TEXT_JUST_VERT	GetVertJust() const { return m_VertJust ; };
	std::string		GetVertJustText() const;
	void			SetHorizJust(TEXT_JUST_HORIZ v) { m_HorizJust = v; CalcExtents(); };
	void			SetHorizJust(const std::string& Text);
	TEXT_JUST_HORIZ	GetHorizJust() const { return m_HorizJust; };
	std::string		GetHorizJustText() const;
	void			SetExtents(const math::Vec2& TopLeft, const math::Vec2& BoxExtents);

	// editable?
	void			SetCanEdit(bool b);
	bool			IsEditable() const { return m_CanEdit; };
	void			SetCanEditMultiline(bool b);
	bool			CanEditMultiline() const { return m_CanEditMultiline; }

	void			KeyPressed(input::Keyboard::KEY* pKey);
	void			CharReceived(unsigned int Key);

	void			SetOwner(UIWidget* pWidget) { m_pOwner = pWidget; };
	void			RefreshText();
	void			SelectAll();
	void			SelectRegion(const math::Vec2& From, const math::Vec2& To);
	void			PutCursor(const math::Vec2& Pos);
	void			SetClip(bool b) { m_Clip = b; };
	void			TrimSpaces();
	void			SetUnderline(bool b) { m_HasUnderline = b; };
	bool			GetUnderline() const {return m_HasUnderline; };

	void			SetPassword(bool b) { m_IsPassword = b; };

	// static variable:
	// global state to deal with JAPANESE, CHINESE AND KOREAN languages ALWAYS being left-aligned
	static bool		s_ForceLeft;
	static void		ForceLeftAlign(bool b) { s_ForceLeft = b; };

	// static variable:
	// state to determine if cursor is insertion-style cursor or block cursor
	static bool		s_InsertionCursor; // may enum this if more than 1 style is available (and we want/need this many)
	static void		SetCursorType(bool b) { s_InsertionCursor = b; };

	static std::string		MapHorizJustToString(TEXT_JUST_HORIZ t);
	static TEXT_JUST_HORIZ	MapStringToHorizJust(const std::string& t);
	static std::string		MapVertJustToString(TEXT_JUST_VERT t);
	static TEXT_JUST_VERT	MapStringToVertJust(const std::string& t);

	typedef bool (*TestValidCharCB)(unsigned short);
	void					SetValidCharCB(TestValidCharCB pCB) { m_ValidCharCB = pCB; };
public:
	void			CalcExtents();
	bool			CapText();
	void			RecalcCursor();
	int				GetIndexFromPos(const math::Vec2& Pos);
	void			DrawUnderline();

							// update
	bool					Tick();

	math::Vec2				m_Pos;			// extents of text
	math::Vec2				m_Size;			// extents of text
	math::Vec2				m_Border;

	// placement info

	TEXT_JUST_VERT			m_VertJust;
	TEXT_JUST_HORIZ			m_HorizJust;
	math::Vec2				m_TopLeft;		// top left corner of designated box
	math::Vec2				m_BoxExtents;	// extents of box

	std::wstring			m_Text;
	std::wstring			m_OriginalText;	//! text before localization db got to it
	unsigned int			m_Flags;
	std::string				m_Font;
	Font*					m_pFont;
	COLOR				m_Color;

	float					m_BlinkTime;
	bool					m_BlinkOn;
	int						m_CursorFrom, m_CursorTo;
	int						m_CursorPrevFrom, m_CursorPrevTo;
	int						m_MaxInputLen;
	math::Vec2				m_Offset;

	math::Vec2				m_CursorSize, m_CursorPos;

	UISprite*				m_Blink;
	bool					m_CanEdit;
	bool					m_CanEditMultiline;
	bool					m_SwearFilter;
	bool					m_HasUnderline;
	UIWidget*				m_pOwner;

	bool					m_MultiLine;
	bool					m_Clip;
	bool					m_IsPassword;
	TestValidCharCB			m_ValidCharCB;
};

}  // namespace ui

#endif // _UI_TEXT_H_